(function (window) {
  var Muuri = window.Muuri;

  QUnit.module('Grid events');

  QUnit.test(
    'send: should be triggered in the end of the send procedure (for the sending grid)',
    function (assert) {
      assert.expect(11);

      var containerA = utils.createGridElements();
      var containerB = utils.createGridElements();
      var gridA = new Muuri(containerA);
      var gridB = new Muuri(containerB);
      var item = gridA.getItems()[0];
      var teardown = function () {
        gridA.destroy();
        gridB.destroy();
        containerA.parentNode.removeChild(containerA);
        containerB.parentNode.removeChild(containerB);
      };

      gridA.on('send', function (data) {
        assert.strictEqual(arguments.length, 1, 'callback: should receive one argument');
        assert.strictEqual(
          Object.prototype.toString.call(data),
          '[object Object]',
          'callback: the argument should be a plain object'
        );
        assert.strictEqual(
          Object.keys(data).length,
          5,
          'callback: the argument should have 5 properties'
        );
        assert.strictEqual(
          data.item,
          item,
          'callback: the argument item property should be the moved item'
        );
        assert.strictEqual(
          data.fromGrid,
          gridA,
          'callback: the argument fromGrid property should be the sending grid instance'
        );
        assert.strictEqual(
          data.fromIndex,
          0,
          'callback: the argument fromIndex property should be the index where the item was moved from'
        );
        assert.strictEqual(
          data.toGrid,
          gridB,
          'callback: the argument toGrid property should be the receiving grid instance'
        );
        assert.strictEqual(
          data.toIndex,
          1,
          'callback: the argument toIndex property should be the index where the item was moved to'
        );
        assert.strictEqual(
          data.toGrid.getItems().indexOf(data.item),
          data.toIndex,
          'callback: the item should be included in the target grid in correct position'
        );
        assert.strictEqual(
          data.fromGrid.getItems().indexOf(data.item),
          -1,
          'callback: the item should not be included in the source grid'
        );
        assert.strictEqual(
          data.item.getElement().parentNode,
          document.body,
          'callback: the item element should be appended to the send container'
        );
      });
      gridB.on('send', function () {
        assert.ok(false, 'should not be triggered for the receiving grid');
      });
      gridA.send(item, gridB, 1, { layout: false });
      teardown();
    }
  );

  QUnit.test(
    'send: should be triggered when an item is dragged into another grid (for the sending grid)',
    function (assert) {
      assert.expect(11);

      var done = assert.async();
      var containerA = utils.createGridElements({
        containerStyles: {
          position: 'absolute',
          left: '0px',
          top: '0px',
          width: '50px',
        },
        itemStyles: {
          position: 'absolute',
          height: '50px',
          width: '100%',
          margin: '10px',
          background: '#000',
        },
      });
      var containerB = utils.createGridElements({
        containerStyles: {
          position: 'absolute',
          left: '70px',
          top: '0px',
          width: '50px',
        },
        itemStyles: {
          position: 'absolute',
          height: '50px',
          width: '100%',
          margin: '10px',
          background: '#000',
        },
      });
      var grids = [];
      var gridA = new Muuri(containerA, {
        dragEnabled: true,
        dragSort: function () {
          return grids;
        },
        dragSortInterval: 100,
        dragSortPredicate: {
          threshold: 50,
          action: 'move',
        },
      });
      var gridB = new Muuri(containerB, {
        dragEnabled: true,
        dragSort: function () {
          return grids;
        },
        dragSortInterval: 100,
        dragSortPredicate: {
          threshold: 50,
          action: 'move',
        },
      });
      var item = gridA.getItems()[0];
      var teardown = function () {
        gridA.destroy();
        gridB.destroy();
        containerA.parentNode.removeChild(containerA);
        containerB.parentNode.removeChild(containerB);
        done();
      };

      grids.push(gridA, gridB);

      gridA.on('send', function (data) {
        assert.strictEqual(arguments.length, 1, 'callback: should receive one argument');
        assert.strictEqual(
          Object.prototype.toString.call(data),
          '[object Object]',
          'callback: the argument should be a plain object'
        );
        assert.strictEqual(
          Object.keys(data).length,
          5,
          'callback: the argument should have 5 properties'
        );
        assert.strictEqual(
          data.item,
          item,
          'callback: the argument item property should be the dragged item'
        );
        assert.strictEqual(
          data.fromGrid,
          gridA,
          'callback: the argument fromGrid property should be the sending grid instance'
        );
        assert.strictEqual(
          data.fromIndex,
          0,
          'callback: the argument fromIndex property should be the index where the item was moved from'
        );
        assert.strictEqual(
          data.toGrid,
          gridB,
          'callback: the argument toGrid property should be the receiving grid instance'
        );
        assert.strictEqual(
          data.toIndex,
          0,
          'callback: the argument toIndex property should be the index where the item was moved to'
        );
        assert.strictEqual(
          data.toGrid.getItems().indexOf(data.item),
          data.toIndex,
          'callback: the item should be included in the target grid in correct position'
        );
        assert.strictEqual(
          data.fromGrid.getItems().indexOf(data.item),
          -1,
          'callback: the item should not be included in the source grid'
        );
        assert.strictEqual(
          data.item.isDragging(),
          true,
          'callback: the item should be in dragging state'
        );
      });

      utils.dragElement({
        element: item.getElement(),
        x: 70,
        y: 0,
        onFinished: teardown,
      });
    }
  );
})(this);
